// 📁 service/impl/ReservationServiceImpl.java
package com.library.management.service.impl;

import com.library.management.entity.Book;
import com.library.management.entity.Reservation;
import com.library.management.entity.User;
import com.library.management.enums.ReservationStatus;
import com.library.management.repository.BookRepository;
import com.library.management.repository.ReservationRepository;
import com.library.management.repository.UserRepository;
import com.library.management.service.ReservationService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
/**
 * 预约服务实现类
 * 处理预约相关的业务逻辑实现
 */
@Service
@Transactional
@RequiredArgsConstructor
@Slf4j
public class ReservationServiceImpl implements ReservationService {

    private final ReservationRepository reservationRepository;
    private final UserRepository userRepository;
    private final BookRepository bookRepository;

    // 预约有效期（天）
    private static final int RESERVATION_VALID_DAYS = 7;

    @Override
    public Reservation save(Reservation reservation) {
        log.info("保存预约记录: {}", reservation.getId());
        return reservationRepository.save(reservation);
    }

    @Override
    public Reservation update(Long id, Reservation reservation) {
        log.info("更新预约记录: {}", id);

        Reservation existingReservation = reservationRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("预约记录不存在: " + id));

        // 更新允许修改的字段
        existingReservation.setExpireDate(reservation.getExpireDate());
        existingReservation.setStatus(reservation.getStatus());
        existingReservation.setNotifySent(reservation.getNotifySent());
        existingReservation.setPriority(reservation.getPriority());

        return reservationRepository.save(existingReservation);
    }

    @Override
    public void delete(Long id) {
        log.info("删除预约记录: {}", id);
        reservationRepository.deleteById(id);
    }


    @Override
    public Optional<Reservation> findById(Long id) {
        return reservationRepository.findById(id);
    }

   @Override
    public Reservation getById(Long id) {
        return reservationRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("预约记录不存在: " + id));
    }
    @Override
    public List<Reservation> findAll() {
        return reservationRepository.findAll();
    }

    @Override
    public Page<Reservation> findAll(Pageable pageable) {
        return reservationRepository.findAll(pageable);
    }

    @Override
    public boolean exists(Long id) {
        return reservationRepository.existsById(id);
    }

    @Override
    public Reservation createReservation(Long userId, Long bookId, LocalDateTime reserveDate, LocalDateTime expireDate) {
        log.info("用户 {} 预约图书 {}", userId, bookId);

        User user = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("用户不存在: " + userId));
        Book book = bookRepository.findById(bookId)
                .orElseThrow(() -> new RuntimeException("图书不存在: " + bookId));

        // 检查用户是否已经有有效的预约
        if (hasActiveReservation(userId, bookId)) {
            throw new RuntimeException("用户已经预约了该图书且预约有效");
        }

        // 创建预约记录
        Reservation reservation = new Reservation();
        reservation.setUser(user);
        reservation.setBook(book);
        reservation.setReserveDate(reserveDate != null ? reserveDate : LocalDateTime.now());
        reservation.setExpireDate(expireDate != null ? expireDate : LocalDateTime.now().plusDays(RESERVATION_VALID_DAYS));
        reservation.setStatus(ReservationStatus.PENDING);
        reservation.setNotifySent(false);
        // 优先级可以根据业务规则设置，例如VIP用户优先级更高
        reservation.setPriority(0);

        return reservationRepository.save(reservation);
    }

    @Override
    public Reservation cancelReservation(Long reservationId) {
        log.info("取消预约: {}", reservationId);

        Reservation reservation = reservationRepository.findById(reservationId)
                .orElseThrow(() -> new RuntimeException("预约记录不存在: " + reservationId));

        if (reservation.getStatus() != ReservationStatus.PENDING) {
            throw new RuntimeException("只能取消等待中的预约");
        }

        reservation.setStatus(ReservationStatus.CANCELLED);
        return reservationRepository.save(reservation);
    }

    @Override
    public Reservation markReservationAsAvailable(Long reservationId) {
        log.info("标记预约为可借阅: {}", reservationId);

        Reservation reservation = reservationRepository.findById(reservationId)
                .orElseThrow(() -> new RuntimeException("预约记录不存在: " + reservationId));

        if (reservation.getStatus() != ReservationStatus.PENDING) {
            throw new RuntimeException("只能将等待中的预约标记为可借阅");
        }

        reservation.setStatus(ReservationStatus.AVAILABLE);
        return reservationRepository.save(reservation);
    }

    @Override
    public List<Reservation> findByUserId(Long userId) {
        return reservationRepository.findByUserId(userId);
    }

    @Override
    public List<Reservation> findByBookId(Long bookId) {
        return reservationRepository.findByBookId(bookId);
    }

    @Override
    public List<Reservation> findByStatus(ReservationStatus status) {
        return reservationRepository.findByStatus(status);
    }

    @Override
    public List<Reservation> findValidReservations() {
        return reservationRepository.findValidReservations(LocalDateTime.now());
    }

    @Override
    public List<Reservation> findExpiredReservations() {
        return reservationRepository.findExpiredReservations(LocalDateTime.now());
    }

    @Override
    public boolean hasActiveReservation(Long userId, Long bookId) {
        return reservationRepository.existsActiveReservationByUserAndBook(userId, bookId, LocalDateTime.now());
    }

    @Override
    public List<Reservation> findReservationQueueByBookId(Long bookId) {
        return reservationRepository.findReservationQueueByBookId(bookId);
    }

    @Override
    public long countByUserId(Long userId) {
        return reservationRepository.countByUserId(userId);
    }

    @Override
    public long countByBookId(Long bookId) {
        return reservationRepository.countByBookId(bookId);
    }

    @Override
    public List<Reservation> findReservationsNeedNotification() {
        return reservationRepository.findReservationsNeedNotification();
    }

    @Override
    public void markNotificationSent(Long reservationId) {
        Reservation reservation = reservationRepository.findById(reservationId)
                .orElseThrow(() -> new RuntimeException("预约记录不存在: " + reservationId));

        reservation.setNotifySent(true);
        reservationRepository.save(reservation);
    }

    @Override
    public List<Reservation> findReservationsExpiringSoon(int days) {
        LocalDateTime currentTime = LocalDateTime.now();
        LocalDateTime expireTime = currentTime.plusDays(days);
        return reservationRepository.findReservationsExpiringSoon(currentTime, expireTime);
    }

    @Override
    public void processExpiredReservations() {
        List<Reservation> expiredReservations = findExpiredReservations();
        for (Reservation reservation : expiredReservations) {
            reservation.setStatus(ReservationStatus.EXPIRED);
            reservationRepository.save(reservation);
        }
        log.info("处理了 {} 个过期预约", expiredReservations.size());
    }

    @Override
    public Page<Reservation> findByUserId(Long userId, Pageable pageable) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("用户不存在: " + userId));
        return (Page<Reservation>) reservationRepository.findByUser(user, pageable);
    }

    @Override
    public Reservation findByUserIdAndBookId(Long userId, Long bookId) {
        return reservationRepository.findByUserIdAndBookId(userId, bookId)
                .orElseThrow(() -> new RuntimeException("预约记录不存在"));
    }
}